/*jslint */
/*globals setTimeout, Class */

/**
 * Класс списка элементов.
 *
 * @class
 * @name List
 */
var List = Class.$extend({

    /**
     * Список элементов.
     *
     * @private
     * @field
     * @name List#list
     * @see List#getList
     * @type {Array}
     */
    list : null,

    /**
     * Длина списка элементов.
     *
     * @private
     * @field
     * @name List#length
     * @see List#getLength
     * @type {Number}
     */
    length : null,

    /**
     * Конструктор.
     *
     * @public
     * @function
     * @constructs
     * @name List#$init
     * @param {Array|List} [list] Список элементов.
     *        Если будет передано что-то другое, кроме указанных типов, то
     *        данные будут просто проигнорированы.
     * @return {void}
     */
    $init : function (list) {
        'use strict';
        var index, length;
        // Заполняем список элементов.
        this.list = [];
        if (list instanceof List) {
            list = list.getList();
        }
        if (list instanceof Array) {
            length = list.length;
            for (index = 0; index < length; index += 1) {
                this.list[index] = list[index];
            }
        }
        // Длина списка элементов.
        this.length = this.list.length;
    },

    /**
     * Получить длину списка элементов.
     *
     * @public
     * @function
     * @name List#getLength
     * @see List#length
     * @return {Number}
     */
    getLength : function () {
        'use strict';
        return this.length;
    },

    /**
     * Получить элемент по индексу.
     *
     * @public
     * @function
     * @name List#getItem
     * @param {Number} index Индекс элемента в списке.
     * @return {*|null}
     */
    getItem : function (index) {
        'use strict';
        index = parseInt(index, 10);
        if (index >= 0 || index < this.length) {
            return this.list[index];
        }
        return null;
    },

    /**
     * Призкак, что список пустой.
     *
     * @public
     * @function
     * @name List#isEmpty
     * @see List#length
     * @return {Boolean}
     */
    isEmpty : function () {
        'use strict';
        return !this.length;
    },

    /**
     * Получить список элементов в виде массива.
     *
     * @public
     * @function
     * @name List#getList
     * @see List#list
     * @return {Array}
     */
    getList : function () {
        'use strict';
        return this.list;
    },

    /**
     * Итерация списка элементов.
     *
     * @public
     * @function
     * @name List#forEach
     * @param {Function} callback Обработчик одного элемента списка. Обработчик
     *        работает в контексте текущего элемента, первым аргументом
     *        принимает элемент списка, а вторым - индекс.
     * @return {void}
     */
    forEach : function (callback) {
        'use strict';
        var index,
            self   = this,
            length = this.list.length;
        function loop(value, index) {
            setTimeout(function () {
                callback.call(value, value, index, self);
            }, 1);
        }
        if (typeof callback !== 'function') {
            throw new TypeError('Обработчик одного элемента списка задан неверным значением, ожидается функция.');
        }
        for (index = 0; index < length; index += 1) {
            loop(this.list[index], index);
        }
    }

});